using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Net;
using System.Web;
using System.IO;
using System.Xml;

using Barbar.MapReport.Configuration;
using Barbar.MapReport.Common;

namespace Barbar.MapReport.GeoCoding {
  public class GeocoderService {
    public GeocoderResponse GeocodeAddress(string address, string googleAPIKey) {
      return GeocodeAddresses(new string[] { address }, googleAPIKey)[0];
    }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
    public GeocoderResponse[] GeocodeAddresses(string[] address, string googleAPIKey) {
      GeocoderResponse[] responses = new GeocoderResponse[address.Length];
      NumberFormatInfo formatInfo = new NumberFormatInfo();
      formatInfo.NumberDecimalSeparator = ".";

      for (int i = 0; i < address.Length; i++) {
        responses[i] = new GeocoderResponse();
        responses[i].Request = WebRequest.Create(String.Format(CultureInfo.InvariantCulture, MapConfigurationManager.GeocoderUrl, HttpUtility.UrlEncode(address[i]), googleAPIKey));
        responses[i].Result = responses[i].Request.BeginGetResponse(null, null);
      }
      for (int i = 0; i < address.Length; i++) {
        WebResponse response;
        try {
          responses[i].RequestOk = true;
          response = responses[i].Request.EndGetResponse(responses[i].Result);
        } catch (Exception exception) {
          responses[i].RequestOk = false;
          responses[i].ExceptionDetail = exception.ToString();
          continue;
        }
        string[] contentType = response.ContentType.Split(';');
        string content = null;
        foreach (string currentContent in contentType) {
          if (currentContent.Trim().StartsWith("charset=", StringComparison.Ordinal)) {
            content = currentContent.Trim();
            content = content.Substring("charset=".Length);
            break;
          }
        }
        if (content != null) {
          using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(content))) {
            responses[i].Xml = reader.ReadToEnd();
            reader.Close();
          }
        } else
          using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
            responses[i].Xml = reader.ReadToEnd();
            reader.Close();
          }
        XmlDocument document = new XmlDocument();
        document.LoadXml(responses[i].Xml);
        XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
        manager.AddNamespace("earth", "http://earth.google.com/kml/2.0");
        XmlNodeList nodes = document.SelectNodes("/earth:kml/earth:Response/earth:Placemark/earth:Point", manager);
        List<GeoPoint> coordinates = new List<GeoPoint>();
        foreach (XmlElement element in nodes) {
          string[] coords = element.InnerText.Split(',');
          coordinates.Add(new GeoPoint(decimal.Parse(coords[1], formatInfo), decimal.Parse(coords[0], formatInfo)));
        }
        responses[i].Points = coordinates.ToArray();
      }
      return responses;
    }
  }
}
